package com.sudoku.board;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.sudoku.observer.Event;
import com.sudoku.observer.Subject;
import com.sudoku.screen.PuzzleLoadingScreen;
import com.sudoku.utility.Constants;
import com.sudoku.utility.Locator;

public class TableButtons implements Constants {

	private char numberSelected;
	private Subject subject;
	private GameHandler handler;
	private Stage stage;
	private BitmapFont smallFont, smallerFont;
	private TextButton undoButton, newGameButton, pencilButton, eraseButton, hintButton;
	private ImageButton menuButton;
	private TextButtonStyle textButtonStyle, numberButtonStyle;
	private NinePatch patch;
	private ShapeRenderer buttonHover, pencilModeBox;
	private int buttonID;
	private boolean buttonDown, pencilMode;
	private Color touchColor, pencilColor, buttonColor;

	public float X_POS = ACTUAL_VIRTUAL_WIDTH * 0.02f;
	public float X_POS2_NUM = ACTUAL_VIRTUAL_WIDTH * 0.04f;
	public float Y_POS = ACTUAL_VIRTUAL_HEIGHT * 0.80f;
	public float Y_POS_BUTTON = ACTUAL_VIRTUAL_HEIGHT * 0.40f;
	public float X_POS2 = X_POS + ACTUAL_VIRTUAL_WIDTH * 0.065f;
	public float X_SPACING = ACTUAL_VIRTUAL_WIDTH * 0.08f;
	public float X_SPACING_BUTTONS = ACTUAL_VIRTUAL_WIDTH * 0.14f;
	public float Y_SPACING = ACTUAL_VIRTUAL_HEIGHT * 0.15f;
	public float Y_SPACING_BUTTON = ACTUAL_VIRTUAL_HEIGHT * 0.18f;
	public float PANEL_WIDTH = ACTUAL_VIRTUAL_WIDTH * 0.07f;
	public float PANEL_HEIGHT = ACTUAL_VIRTUAL_HEIGHT * 0.10f;
	public float PANEL_WIDTH_BUTTON = ACTUAL_VIRTUAL_WIDTH * 0.11f;
	public float PANEL_HEIGHT_BUTTON = ACTUAL_VIRTUAL_HEIGHT * 0.11f;

	public TableButtons(GameHandler handler, Subject subject) {
		numberSelected = 1;
		this.subject = subject;
		patch = new NinePatch(Locator.getAssets().get(PANEL_PATH, Texture.class));
		this.handler = handler;
		stage = new Stage();
		touchColor = new Color(0.0f, 0f, 1.0f, 0.2f);
		pencilColor = new Color(0.0f, 1.0f, 0.0f, 0.3f);
		buttonColor = new Color(1, 1, 0, 0.2f);
		buttonDown = false;
		buttonID = 0;
		stage.setViewport(Locator.getViewport());
		Locator.getInputMultiplexer().addProcessor(stage);

		// fonts
		FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal(FONT));
		FreeTypeFontParameter param = new FreeTypeFontParameter();
		param.size = (int) (60);
		smallFont = generator.generateFont(param);
		smallFont.setColor(Color.BLACK);
		param.size = (int) (60);
		smallerFont = generator.generateFont(param);
		smallerFont.setColor(Color.BLACK);
		generator.dispose();

		textButtonStyle = new TextButtonStyle();
		textButtonStyle.pressedOffsetX = 1;
		textButtonStyle.pressedOffsetY = -1;
		textButtonStyle.font = smallFont;
		textButtonStyle.fontColor = Color.BLACK;

		numberButtonStyle = new TextButtonStyle(textButtonStyle);
		numberButtonStyle.font = smallerFont;

		createNumberButtons();
		createOtherButtons();

		newGameButton.setPosition(X_POS, Y_POS_BUTTON);
		eraseButton.setPosition(X_POS + X_SPACING_BUTTONS, Y_POS_BUTTON);
		pencilButton.setPosition(X_POS + X_SPACING_BUTTONS * 2, Y_POS_BUTTON);
		hintButton.setPosition(X_POS2, Y_POS_BUTTON - Y_SPACING_BUTTON);
		undoButton.setPosition(X_POS2 + X_SPACING_BUTTONS, Y_POS_BUTTON - Y_SPACING_BUTTON);
		menuButton.setPosition(ACTUAL_VIRTUAL_WIDTH * 0.02f, ACTUAL_VIRTUAL_HEIGHT * 0.02f);

		buttonHover = new ShapeRenderer();
		buttonHover.setTransformMatrix(stage.getCamera().view);
		buttonHover.setProjectionMatrix(stage.getCamera().projection);

		pencilModeBox = new ShapeRenderer();
		pencilModeBox.setTransformMatrix(stage.getCamera().view);
		pencilModeBox.setProjectionMatrix(stage.getCamera().projection);
	}

	public void render(SpriteBatch sb) {
		stage.draw();

		sb.begin();
		//draw background for number buttons
		for (int i = 0; i < 9; i++) {
			if (i < 5) {
				patch.draw(sb, X_POS + X_SPACING * i, Y_POS, PANEL_WIDTH, PANEL_HEIGHT);
			} else {
				patch.draw(sb, X_POS + X_POS2_NUM + X_SPACING * (i - 5), Y_POS - Y_SPACING, PANEL_WIDTH, PANEL_HEIGHT);
			}
		}
		//draw background for regular buttons
		patch.draw(sb, X_POS + X_SPACING_BUTTONS * 0, Y_POS_BUTTON, PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON); //new game
		patch.draw(sb, X_POS + X_SPACING_BUTTONS * 1, Y_POS_BUTTON, PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON); //erase
		patch.draw(sb, X_POS + X_SPACING_BUTTONS * 2, Y_POS_BUTTON, PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON); //pencil
		patch.draw(sb, X_POS2 + X_SPACING_BUTTONS * 0, Y_POS_BUTTON - Y_SPACING_BUTTON, PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON); //hint
		patch.draw(sb, X_POS2 + X_SPACING_BUTTONS * 1, Y_POS_BUTTON - Y_SPACING_BUTTON, PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON); //undo

		sb.end();
		drawHoverColor();
	}

	private void drawHoverColor() {
		Gdx.gl.glEnable(GL20.GL_BLEND);
		Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
		buttonHover.begin(ShapeType.Filled);
		buttonHover.setColor(touchColor);
		if (buttonDown) {
			switch (buttonID) {
			case 1:
			case 2:
			case 3:
			case 4:
			case 5:
				buttonHover.rect(X_POS + X_SPACING * (buttonID - 1), Y_POS, PANEL_WIDTH, PANEL_HEIGHT);
				break;
			case 6:
			case 7:
			case 8:
			case 9:
				buttonHover.rect(X_POS + X_POS2_NUM + X_SPACING * (buttonID - 1 - 5), Y_POS - Y_SPACING, PANEL_WIDTH, PANEL_HEIGHT);
				break;
			case 11: //new game
				buttonHover.setColor(buttonColor);
				buttonHover.rect(X_POS + X_SPACING_BUTTONS * 0, Y_POS_BUTTON, PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON);
				break;
			case 12: //erase
				buttonHover.setColor(buttonColor);
				buttonHover.rect(X_POS + X_SPACING_BUTTONS * 1, Y_POS_BUTTON, PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON);
				break;
			case 13: //hint
				buttonHover.setColor(buttonColor);
				buttonHover.rect(X_POS2 + X_SPACING_BUTTONS * 0, Y_POS_BUTTON - Y_SPACING_BUTTON, PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON);
				break;
			case 14: //undo
				buttonHover.setColor(buttonColor);
				buttonHover.rect(X_POS2 + X_SPACING_BUTTONS * 1, Y_POS_BUTTON - Y_SPACING_BUTTON, PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON);
				break;
			default:
				break;
			}
		}
		if (pencilMode) {
			buttonHover.setColor(pencilColor);
			buttonHover.rect(X_POS + X_SPACING_BUTTONS * 2, Y_POS_BUTTON, PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON);
		}
		buttonHover.end();
		Gdx.gl.glDisable(GL20.GL_BLEND);

	}

	public void update(float delta) {
		stage.act(delta);
	}

	public char getNumberSelected() {
		return numberSelected;
	}

	public void setNumberSelected(char numberSelected) {
		this.numberSelected = numberSelected;
	}

	private void createOtherButtons() {
		undoButton = new TextButton("Undo", textButtonStyle);
		undoButton.addListener(new ClickListener() {
			@Override
			public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
				handler.undo();
				buttonDown = false;
			}

			@Override
			public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
				buttonID = 14;
				subject.notify(Event.EVENT_BUTTON_CLICK);
				buttonDown = true;
				return true;
			}
		});
		undoButton.setSize(PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON);
		stage.addActor(undoButton);

		newGameButton = new TextButton("New", textButtonStyle);
		newGameButton.addListener(new ClickListener() {
			@Override
			public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
				PuzzleLoadingScreen next = Locator.getGame().getPuzzleLoadingScreen();
				Locator.getGame().setScreen(next);
				subject.notify(Event.EVENT_SHOW_LOAD_SCREEN);
				buttonDown = false;
			}

			@Override
			public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
				buttonID = 11;
				buttonDown = true;
				subject.notify(Event.EVENT_BUTTON_CLICK);
				return true;
			}
		});
		newGameButton.setSize(PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON);
		stage.addActor(newGameButton);

		/*debugButton = new TextButton("Show", textButtonStyle);
		debugButton.addListener(new ClickListener() {
			@Override
			public void clicked(InputEvent event, float x, float y) {
				subject.notify(Event.EVENT_CLICK);
				handler.debug();
			}
		});

		debugButton.setPosition(X_POS, ACTUAL_VIRTUAL_HEIGHT * 0.3f);
		stage.addActor(debugButton);*/

		eraseButton = new TextButton("Erase", textButtonStyle);
		eraseButton.addListener(new ClickListener() {
			@Override
			public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
				subject.notify(Event.EVENT_ERASE);
				buttonDown = false;
			}

			@Override
			public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
				buttonID = 12;
				buttonDown = true;
				subject.notify(Event.EVENT_BUTTON_CLICK);
				return true;
			}
		});
		eraseButton.setSize(PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON);
		stage.addActor(eraseButton);

		pencilButton = new TextButton("Pencil", textButtonStyle);
		pencilButton.addListener(new ClickListener() {
			@Override
			public void clicked(InputEvent event, float x, float y) {
				subject.notify(Event.EVENT_PENCIL);
				subject.notify(Event.EVENT_BUTTON_CLICK);
				pencilMode = !pencilMode;
			}
		});
		pencilButton.setSize(PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON);
		stage.addActor(pencilButton);

		menuButton = new ImageButton(new Image(Locator.getAssets().get(MENU_ARROW, Texture.class)).getDrawable());
		menuButton.setScale(0.3f);
		menuButton.getImage().setScale(0.3f);
		menuButton.addListener(new ClickListener() {
			@Override
			public void clicked(InputEvent event, float x, float y) {
				subject.notify(Event.EVENT_GAME_TO_MENU);
				subject.notify(Event.EVENT_CLICK);
			}
		});

		stage.addActor(menuButton);

		hintButton = new TextButton("Hint", textButtonStyle);
		hintButton.addListener(new ClickListener() {
			@Override
			public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
				subject.notify(Event.EVENT_HINT);
				buttonDown = false;
			}

			@Override
			public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
				buttonID = 13;
				buttonDown = true;
				subject.notify(Event.EVENT_BUTTON_CLICK);
				return true;
			}
		});
		hintButton.setSize(PANEL_WIDTH_BUTTON, PANEL_HEIGHT_BUTTON);
		stage.addActor(hintButton);

	}

	public void createNumberButtons() {
		TextButton button = null;
		for (int i = 0; i < 9; i++) {
			button = new TextButton("" + (i + 1), numberButtonStyle);
			button.setSize(PANEL_WIDTH, PANEL_HEIGHT);
			//button.setScale(1.2f);
			final char temp;
			temp = Character.forDigit(i + 1, 10);

			button.addListener(new ClickListener() {
				@Override
				public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
					numberSelected = temp;
					buttonDown = false;
					subject.notify(Event.EVENT_NUMBER_SELECTED);
				}

				@Override
				public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
					buttonID = Character.getNumericValue(temp);
					buttonDown = true;
					subject.notify(Event.EVENT_BUTTON_CLICK);
					return true;
				}

			});
			if (i < 5) {
				button.setPosition(X_POS + X_SPACING * i, Y_POS * 0.99f);
			} else {
				button.setPosition(X_POS + X_POS2_NUM + X_SPACING * (i - 5), Y_POS * 0.99f - Y_SPACING);
			}
			stage.addActor(button);
		}

	}
}
